﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Globalization;

namespace Silverlight.InputCtrl
{
    public enum OperatorCompare
    {
        Equal,
        NotEqual,
        GreaterThan,
        GreaterThanEqual,
        LessThan,
        LessThanEqual,
        DataTypeCheck,
    }
    public enum CompareDataType
    {
        String,
        Integer,
        Double,
        Date,
        Time
    }

    public enum CompareTimeType
    {
        Hours12,
        Hours24
    }
    
    public class CompareValidator : ValidatorBase
    {

        private enum ValidCompareControl
        {
            Other,
            TextBlock,
            TextBox,
            PasswordBox
        }

        private CultureInfo CultureCompare
        {
            get { return (CultureInfo)GetValue(CultureCompareProperty); }
            set { SetValue(CultureCompareProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CultureCompare.  This enables animation, styling, binding, etc...
        private static readonly DependencyProperty CultureCompareProperty =
            DependencyProperty.Register("CultureCompare", typeof(CultureInfo), typeof(CompareValidator), new PropertyMetadata(new CultureInfo(System.Threading.Thread.CurrentThread.CurrentCulture.ToString())));

        public string CultureInput
        {
            get { return (string)GetValue(CultureInputProperty); }
            set { SetValue(CultureInputProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CultureValidate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CultureInputProperty =
            DependencyProperty.Register("CultureInput", typeof(string), typeof(CompareValidator), new PropertyMetadata("", CultureInputPropertyCallBack));

        private static void CultureInputPropertyCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            try
            {
                d.SetValue(CultureCompareProperty,
                    new CultureInfo((string)e.NewValue));
            }
            catch
            {
                d.SetValue(CultureCompareProperty, System.Threading.Thread.CurrentThread.CurrentCulture);
            }
        }

        public CompareDataType DataType
        {
            get { return (CompareDataType)GetValue(DataTypeProperty); }
            set { SetValue(DataTypeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataTye.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataTypeProperty =
            DependencyProperty.Register("DataType", typeof(CompareDataType), typeof(CompareValidator), new PropertyMetadata(CompareDataType.String));

        public CompareTimeType TimeType
        {
            get { return (CompareTimeType)GetValue(TimeTypeProperty); }
            set { SetValue(TimeTypeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataTye.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TimeTypeProperty =
            DependencyProperty.Register("TimeType", typeof(CompareTimeType), typeof(CompareValidator), new PropertyMetadata(CompareTimeType.Hours24));

        public string ValueToCompare
        {
            get { return (string)GetValue(ValueToCompareProperty); }
            set { SetValue(ValueToCompareProperty, value); }
        }

        public static readonly DependencyProperty ValueToCompareProperty =
            DependencyProperty.Register("ValueToCompare", typeof(string), typeof(CompareValidator), new PropertyMetadata(""));

        public string ControlToCompare
        {
            get { return (string)GetValue(ControlToCompareProperty); }
            set { SetValue(ControlToCompareProperty, value); }
        }

        public static readonly DependencyProperty ControlToCompareProperty =
            DependencyProperty.Register("ControlToCompare", typeof(string), typeof(CompareValidator), new PropertyMetadata(""));


        public string PropertyControlToCompare
        {
            get { return (string)GetValue(PropertyControlToCompareProperty); }
            set { SetValue(PropertyControlToCompareProperty, value); }
        }

        public static readonly DependencyProperty PropertyControlToCompareProperty =
            DependencyProperty.Register("PropertyControlToCompare", typeof(string), typeof(CompareValidator), new PropertyMetadata(""));

        public OperatorCompare Operator
        {
            get { return (OperatorCompare)GetValue(OperatorProperty); }
            set { SetValue(OperatorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Operator.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OperatorProperty =
            DependencyProperty.Register("Operator", typeof(OperatorCompare), typeof(CompareValidator), new PropertyMetadata(OperatorCompare.Equal));

        public override void InitValidator(FrameworkElement element, string PropertyName)
        {
            base.InitValidator(element, PropertyName);
            if (base.ExceptionValidator == null)
            {
                if (Operator != OperatorCompare.DataTypeCheck)
                {
                    if (String.IsNullOrEmpty(ControlToCompare) && String.IsNullOrEmpty(ValueToCompare))
                    {
                        base.ExceptionValidator = new Exception(Resource.CompareValidator_ValueComapareEmpty);
                    }
                }
            }
            if (base.ExceptionValidator != null)
            {
                base.InitValidator(null,PropertyName);
            }
        }
        private ValidCompareControl GetValidTypeCompare(FrameworkElement compare)
        {
            if (compare is TextBox) return ValidCompareControl.TextBox;
            if (compare is TextBlock) return ValidCompareControl.TextBlock;
            if (compare is PasswordBox) return ValidCompareControl.PasswordBox;
            return ValidCompareControl.Other;
        }

        public override bool Validate()
        {
            base.IsValidResult = true;
            FrameworkElement _elemValidate = base.ElementValidator;
            if (_elemValidate == null || !Enabled)
            {
                return base.IsValidResult;
            }
            FrameworkElement context = null;
            FrameworkElement compare = null;
            ValidCompareControl Typecompare = ValidCompareControl.Other;

            if (Operator != OperatorCompare.DataTypeCheck)
            {
                if (!String.IsNullOrEmpty(ControlToCompare))
                {
                    context = ValidatorManager.GetContextValidator();
                    compare = context.FindName(ControlToCompare) as FrameworkElement;
                    if (compare == null)
                    {
                        throw new Exception(String.Format(Resource.CompareValidator_ControlToCompareNotFound, ControlToCompare));
                    }
                    Typecompare = GetValidTypeCompare(compare);
                    if (Typecompare == ValidCompareControl.Other)
                    {
                        throw new Exception(String.Format(Resource.CompareValidator_ControlToCompareTypeInvalid, compare.GetType().UnderlyingSystemType));
                    }
                }
            }

            string Value = ValidatorCommon.GetValueText(_elemValidate,base.PropertyToValidate);
            if (String.IsNullOrEmpty(Value))
            {
                if (String.IsNullOrEmpty(ControlToCompare))
                {
                    return base.IsValidResult;
                }
            }
            if (DataType == CompareDataType.Time && TimeType == CompareTimeType.Hours12)
            {
                string aux = Value.Substring(0,2);
                int newValue = 0;
                if (!Int32.TryParse(aux, NumberStyles.Integer,CultureCompare, out newValue))
                {
                    base.IsValidResult = false;
                    return base.IsValidResult;
                }
                if (newValue < 0 || newValue > 12)
                {
                    base.IsValidResult = false;
                    return base.IsValidResult;
                }
            }

            base.IsValidResult = false;

            string ValueCompare = String.IsNullOrEmpty(ValueToCompare) ? "" : ValueToCompare;
            if (!String.IsNullOrEmpty(ControlToCompare))
            {
                if (PropertyControlToCompare != "")
                {
                    ValueCompare = ValidatorCommon.GetValueText(compare, PropertyControlToCompare);
                }
                else
                {
                    switch (Typecompare)
                    {
                        case ValidCompareControl.TextBox:
                            ValueCompare = ((TextBox)compare).Text;
                            break;
                        case ValidCompareControl.TextBlock:
                            ValueCompare = ((TextBlock)compare).Text;
                            break;
                        case ValidCompareControl.PasswordBox:
                            ValueCompare = ((PasswordBox)compare).Password;
                            break;
                    }
                }
            }
            if (!String.IsNullOrEmpty(ControlToCompare) && DataType == CompareDataType.Time && TimeType == CompareTimeType.Hours12)
            {
                string aux = ValueCompare.Substring(0, 2);
                int newValue = 0;
                if (!Int32.TryParse(aux, NumberStyles.Integer, CultureCompare, out newValue))
                {
                    base.IsValidResult = false;
                    return base.IsValidResult;
                }
                if (newValue < 0 || newValue > 12)
                {
                    base.IsValidResult = false;
                    return base.IsValidResult;
                }
            }

            switch (DataType)
            {
                case CompareDataType.Integer:
                    {
                        int newValue = 0;
                        if (Operator != OperatorCompare.DataTypeCheck)
                        {
                            if (!int.TryParse(ValueCompare, out newValue))
                            {
                                return base.IsValidResult;
                            }
                        }
                        if (!int.TryParse(Value, out newValue))
                        {
                            return base.IsValidResult;
                        }
                    }
                    break;
                case CompareDataType.Double:
                    {
                        double newValue = 0;
                        if (Operator != OperatorCompare.DataTypeCheck)
                        {
                            if (!double.TryParse(ValueCompare, NumberStyles.Number, CultureCompare, out newValue))
                            {
                                return base.IsValidResult;
                            }
                        }
                        if (!double.TryParse(Value, NumberStyles.Number, CultureCompare, out newValue))
                        {
                            return base.IsValidResult;
                        }
                    }
                    break;
                case CompareDataType.Date:
                case CompareDataType.Time:
                    {
                        DateTime newValue;
                        if (Operator != OperatorCompare.DataTypeCheck)
                        {
                            if (!DateTime.TryParse(ValueCompare, CultureCompare, DateTimeStyles.AssumeLocal, out newValue))
                            {
                                return base.IsValidResult;
                            }
                        }
                        if (!DateTime.TryParse(Value, CultureCompare, DateTimeStyles.AssumeLocal, out newValue))
                        {
                            return base.IsValidResult;
                        }

                    }
                    break;
            }
            if (Operator == OperatorCompare.DataTypeCheck)
            {
                base.IsValidResult = true;
                return base.IsValidResult;
            }
            switch (Operator)
            {
                case OperatorCompare.Equal:
                    base.IsValidResult = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) == 0);
                    break;
                case OperatorCompare.NotEqual:
                    base.IsValidResult = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) != 0);
                    break;
                case OperatorCompare.GreaterThan:
                    {
                        switch (DataType)
                        {
                            case CompareDataType.String:
                                base.IsValidResult = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) < 0);
                                break;
                            case CompareDataType.Integer:
                                {
                                    int a = int.Parse(Value,CultureCompare);
                                    int b = int.Parse(ValueCompare,CultureCompare);
                                    base.IsValidResult = (a > b);
                                }
                                break;
                            case CompareDataType.Double:
                                {
                                    double a = double.Parse(Value, NumberStyles.Number,CultureCompare);
                                    double b = double.Parse(ValueCompare, NumberStyles.Number, CultureCompare);
                                    base.IsValidResult = (a > b);
                                }
                                break;
                            case CompareDataType.Date:
                            case CompareDataType.Time:
                                {
                                    DateTime a = DateTime.Parse(Value, CultureCompare,DateTimeStyles.AssumeLocal);
                                    DateTime b = DateTime.Parse(ValueCompare, CultureCompare, DateTimeStyles.AssumeLocal);
                                    base.IsValidResult = (a > b);
                                }
                                break;
                        }
                    }
                    break;
                case OperatorCompare.GreaterThanEqual:
                    {
                        switch (DataType)
                        {
                            case CompareDataType.String:
                                {
                                    bool aux = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) < 0);
                                    if (!aux)
                                    {
                                        aux = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) == 0);
                                    }
                                    base.IsValidResult = aux;
                                }
                                break;
                            case CompareDataType.Integer:
                                {
                                    int a = int.Parse(Value,CultureCompare);
                                    int b = int.Parse(ValueCompare,CultureCompare);
                                    base.IsValidResult = (a >= b);
                                }
                                break;
                            case CompareDataType.Double:
                                {
                                    double a = double.Parse(Value, NumberStyles.Number, CultureCompare);
                                    double b = double.Parse(ValueCompare, NumberStyles.Number, CultureCompare);
                                    base.IsValidResult = (a >= b);
                                }
                                break;
                            case CompareDataType.Date:
                            case CompareDataType.Time:
                                {
                                    DateTime a = DateTime.Parse(Value, CultureCompare, DateTimeStyles.AssumeLocal);
                                    DateTime b = DateTime.Parse(ValueCompare, CultureCompare, DateTimeStyles.AssumeLocal);
                                    base.IsValidResult = (a >= b);
                                }
                                break;
                        }
                    }
                    break;
                case OperatorCompare.LessThan:
                    {
                        switch (DataType)
                        {
                            case CompareDataType.String:
                                base.IsValidResult = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) > 0);
                                break;
                            case CompareDataType.Integer:
                                {
                                    int a = int.Parse(Value,CultureCompare);
                                    int b = int.Parse(ValueCompare,CultureCompare);
                                    base.IsValidResult = (a < b);
                                }
                                break;
                            case CompareDataType.Double:
                                {
                                    double a = double.Parse(Value, NumberStyles.Number, CultureCompare);
                                    double b = double.Parse(ValueCompare, NumberStyles.Number, CultureCompare);
                                    base.IsValidResult = (a < b);
                                }
                                break;
                            case CompareDataType.Date:
                            case CompareDataType.Time:
                                {
                                    DateTime a = DateTime.Parse(Value, CultureCompare, DateTimeStyles.AssumeLocal);
                                    DateTime b = DateTime.Parse(ValueCompare, CultureCompare, DateTimeStyles.AssumeLocal);
                                    base.IsValidResult = (a < b);
                                }
                                break;
                        }
                    }
                    break;
                case OperatorCompare.LessThanEqual:
                    {
                        switch (DataType)
                        {
                            case CompareDataType.String:
                                {
                                    bool aux = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) > 0);
                                    if (!aux)
                                    {
                                        aux = (String.Compare(Value, ValueCompare, CultureCompare, CompareOptions.StringSort) == 0);
                                    }
                                    base.IsValidResult = aux;
                                }
                                break;
                            case CompareDataType.Integer:
                                {
                                    int a = int.Parse(Value,CultureCompare);
                                    int b = int.Parse(ValueCompare,CultureCompare);
                                    base.IsValidResult = (a <= b);
                                }
                                break;
                            case CompareDataType.Double:
                                {
                                    double a = double.Parse(Value, NumberStyles.Number, CultureCompare);
                                    double b = double.Parse(ValueCompare, NumberStyles.Number, CultureCompare);
                                    base.IsValidResult = (a <= b);
                                }
                                break;
                            case CompareDataType.Date:
                            case CompareDataType.Time:
                                {
                                    DateTime a = DateTime.Parse(Value, CultureCompare, DateTimeStyles.AssumeLocal);
                                    DateTime b = DateTime.Parse(ValueCompare, CultureCompare, DateTimeStyles.AssumeLocal);
                                    base.IsValidResult = (a <= b);
                                }
                                break;
                        }
                    }
                    break;
            }
            return base.IsValidResult;
        }
    }
}
